package core.domain;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.log4j.Logger;


public class AbstractDao<T extends IdEntity> extends SimpleDao implements
		Dao<T> {
	
	public static final Logger logger = Logger.getLogger(AbstractDao.class);

	public T findObject(long oid) {
		return getEm().find(getParameterClass(), oid);
	}

	public List<T> findObjects(long[] oids) {
		CriteriaBuilder cb = getEm().getCriteriaBuilder();
		CriteriaQuery<T> cq = cb.createQuery(getParameterClass());
		Root<T> r = cq.from(getParameterClass());
		Predicate p = r.get("oid").in(oids);
		cq.where(p);
		return getEm().createQuery(cq).getResultList();
	}

	public List<T> findObjects(List<Long> oids) {
		CriteriaBuilder cb = getEm().getCriteriaBuilder();
		CriteriaQuery<T> cq = cb.createQuery(getParameterClass());
		Root<T> r = cq.from(getParameterClass());
		Predicate p = r.get("oid").in(oids);
		cq.where(p);
		return getEm().createQuery(cq).getResultList();
	}

	public T store(T object) {
		logger.info(getEm());
		getEm().persist(object);
		return object;
	}

	public T remove(T object) {
		getEm().remove(object);
		return object;
	}

	public List<T> findAllObjects() {
		CriteriaBuilder cb = getEm().getCriteriaBuilder();
		CriteriaQuery<T> cq = cb.createQuery(getParameterClass());
		Root<T> root = cq.from(getParameterClass());
		cq = cq.select(root);
		return getEm().createQuery(cq).getResultList();
	}

	private Class<T> parameterClass;

	@SuppressWarnings("unchecked")
	protected synchronized  Class<T> getParameterClass() {
		if (null == parameterClass) {
			Type superClassType = getClass().getGenericSuperclass();
			if (superClassType instanceof ParameterizedType) {
				ParameterizedType pt = (ParameterizedType) superClassType;
				parameterClass = (Class<T>) pt.getActualTypeArguments()[0];
			} else {
				throw new IllegalArgumentException(getClass().getName());
			}
		}
		return parameterClass;
	}
}
